package com.trussell.genesis;

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.io.File;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JSplitPane;
import javax.swing.JToolBar;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import com.jme.system.DisplaySystem;
import com.jme.system.canvas.JMECanvas;
import com.jme.system.lwjgl.LWJGLSystemProvider;
import com.jmex.awt.input.AWTMouseInput;
import com.jmex.awt.lwjgl.LWJGLAWTCanvasConstructor;
import com.trussell.genesis.GenesisImplementor.Mode;
import com.trussell.genesis.dialogs.SelectWorkspaceDialog;
import com.trussell.genesis.util.ConfigManager;
import com.trussell.genesis.windowutils.listeners.GenesisComponentListener;
import com.trussell.genesis.windowutils.menus.EditMenu;
import com.trussell.genesis.windowutils.menus.FileMenu;
import com.trussell.genesis.windowutils.menus.ToolMenu;
import com.trussell.genesis.windowutils.menus.ViewMenu;
import com.trussell.genesis.windowutils.toolbars.EffectsToolBar;
import com.trussell.genesis.windowutils.toolbars.ModeToolBar;
import com.trussell.genesis.windowutils.toolbars.TerrainEditToolBar;
import com.trussell.genesis.windowutils.toolbars.WorldEditToolBar;

/**
 * The main window for the editor. This will hold our jME implementation as well
 * as our menus and tools for editing the world.
 * 
 * @author Tyler Trussell
 */
public class Genesis extends JFrame {

	private static final long serialVersionUID = 1L;

	/**
	 * Make this a Singleton class.
	 */
	private static Genesis instance;

	public static Genesis getInstance() {
		if (instance == null)
			instance = new Genesis();
		return instance;
	}

	/*
	 * Stuff to load JME into this editor.
	 */
	Canvas glCanvas;
	GenesisImplementor genesisImpl;

	/*
	 * Declarations for the Menu and Tool bars.
	 */
	private JMenuBar menubar;
	private FileMenu file;
	private EditMenu edit;
	private ViewMenu view;
	private ToolMenu tools;
	private JPanel toolBarPanel;
	private ModeToolBar topToolBar;
	private JToolBar btmToolBar;
	private JSplitPane splitPane;

	/*
	 * Declarations for Workspace
	 */
	File workspace, textures, models, scripts, xml;

	/**
	 * This constructor will set up the editor window.
	 */
	public Genesis() {
		setLNF();
		DisplaySystem.getDisplaySystem().setMinStencilBits(4);
		setTitle("Genesis v0.0010 (ALPHA) -- World Editor by Tyler Trussell");
		setIconImage(new ImageIcon("images/64x64genesislogo.png").getImage());

		/*
		 * Set window to the appropriate size and center it. TODO: make last
		 * window location appear in config.
		 */
		setSize(ConfigManager.getInstance().getDefaultWidth(), ConfigManager
				.getInstance().getDefaultHeight());
		System.out.println(ConfigManager.getInstance().getDefaultWidth()+ "," + ConfigManager
				.getInstance().getDefaultHeight());
		setLocationRelativeTo(null);

		/*
		 * Set up layout manager for the editor.
		 */
		setLayout(new BorderLayout());

		/*
		 * Set up the listeners for the window.
		 */
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		addComponentListener(new GenesisComponentListener());

		/*
		 * Creates window, places in the center of the screen and adjusts the
		 * size to be 768 x 512.
		 */
		constructMenubar();
		toolBarPanel = new JPanel(new BorderLayout());
		topToolBar = new ModeToolBar();
		btmToolBar = new WorldEditToolBar();
		toolBarPanel.add(topToolBar, BorderLayout.NORTH);
		toolBarPanel.add(new JSeparator(), BorderLayout.CENTER);
		toolBarPanel.add(btmToolBar, BorderLayout.SOUTH);
		add(toolBarPanel, BorderLayout.NORTH);

		add(getGlCanvas(), BorderLayout.CENTER);
	}

	/**
	 * Set up the menu bars (File, Edit, etc.) for the primary window.
	 */
	private void constructMenubar() {
		if (menubar == null)
			menubar = new JMenuBar();

		file = new FileMenu();
		edit = new EditMenu();
		view = new ViewMenu();
		tools = new ToolMenu();

		menubar.add(file);
		menubar.add(edit);
		menubar.add(view);
		menubar.add(tools);

		setJMenuBar(menubar);
	}

	/**
	 * Sets up the appropriate LNF. TODO: Handle exceptions
	 */
	private void setLNF() {
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (UnsupportedLookAndFeelException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public JMenuBar getMenubar() {
		return menubar;
	}

	public void setMenubar(JMenuBar menubar) {
		this.menubar = menubar;
	}

	public JToolBar getBtmToolBar() {
		return btmToolBar;
	}

	public void setMode(Mode m) {
		tools.setMode(m);
		topToolBar.setMode(m);
		switch (m) {
		case NONE: // WORLD EDIT MODE
			toolBarPanel.remove(btmToolBar);
			btmToolBar = new WorldEditToolBar();
			toolBarPanel.add(btmToolBar, BorderLayout.SOUTH);
			toolBarPanel.updateUI();
			break;
		case TERRAIN_EDIT: // TERRAIN EDIT MODE
			toolBarPanel.remove(btmToolBar);
			btmToolBar = TerrainEditToolBar.getInstance();
			toolBarPanel.add(btmToolBar, BorderLayout.SOUTH);
			toolBarPanel.updateUI();
			break;
		case EFFECTS_EDIT: // EFFECTS EDIT MODE
			toolBarPanel.remove(btmToolBar);
			btmToolBar = new EffectsToolBar();
			toolBarPanel.add(btmToolBar, BorderLayout.SOUTH);
			toolBarPanel.updateUI();
			break;
		}
	}

	public void setWorkspace(File top) {
		this.workspace = top;
		this.textures = new File(top.getPath() + "/assets/textures");
		this.models = new File(top.getPath() + "/assets/models");
		this.scripts = new File(top.getPath() + "/assets/scripts");
		this.xml = new File(top.getPath() + "/workspace.xml");
		ConfigManager.getInstance().setDefaultWorkspace(top);
	}

	protected Canvas getGlCanvas() {
		if (glCanvas == null) {
			// -------------GL STUFF------------------

			// make the canvas:
			DisplaySystem display = DisplaySystem
					.getDisplaySystem(LWJGLSystemProvider.LWJGL_SYSTEM_IDENTIFIER);
			display.registerCanvasConstructor("AWT",
					LWJGLAWTCanvasConstructor.class);
			glCanvas = (Canvas) display.createCanvas(ConfigManager.getInstance().getDefaultWidth(),
					ConfigManager.getInstance().getDefaultHeight());
			glCanvas.setMinimumSize(new Dimension(512, 256));

			// add a listener... if window is resized, we can do something about
			// it.
			glCanvas.addComponentListener(new ComponentAdapter() {
				public void componentResized(ComponentEvent ce) {
					doResize();
				}
			});
			// Important! Here is where we add the guts to the canvas:
			genesisImpl = GenesisImplementor.getInstance();

			((JMECanvas) glCanvas).setImplementor(genesisImpl);
			GenesisCameraHandler gch = new GenesisCameraHandler(genesisImpl);
			glCanvas.addMouseListener(gch);
			glCanvas.addMouseMotionListener(gch);
			glCanvas.addMouseWheelListener(gch);
			AWTMouseInput.setup(glCanvas, false);
			
			glCanvas.setPreferredSize(new Dimension(1024, 768));
			forceUpdateToSize();
		}
		return glCanvas;
	}

	protected void doResize() {
		if (genesisImpl != null) {
			genesisImpl.resizeCanvas(glCanvas.getWidth(), glCanvas.getHeight());
		}
	}
	
	public Dimension getJMECanvasSize() {
		return glCanvas.getSize();
	}
	
	public void forceUpdateToSize() {
        // force a resize to ensure proper canvas size.
        glCanvas.setSize(glCanvas.getWidth(), glCanvas.getHeight() + 1);
        glCanvas.setSize(glCanvas.getWidth(), glCanvas.getHeight() - 1);
    }
	
	public void recenterCamera() {
		GenesisCameraHandler gch = (GenesisCameraHandler) glCanvas.getMouseListeners()[0];
		gch.recenterCamera();
	}

	public static void main(String args[]) {
		Genesis.getInstance().setVisible(true);
		File workspace = ConfigManager.getInstance().getDefaultWorkspace();
		while (workspace == null) {
			new SelectWorkspaceDialog();
			workspace = ConfigManager.getInstance().getDefaultWorkspace();
		}
		if (!SelectWorkspaceDialog.hasIntegrity(workspace)) {
			JOptionPane.showMessageDialog(null, "Workspace Corrupted.\n"
					+ "You will be prompted\n" + "to enter a new workspace.");
			workspace = null;
			while (workspace == null) {
				new SelectWorkspaceDialog();
				workspace = ConfigManager.getInstance().getDefaultWorkspace();
			}
		}
		Genesis.getInstance().setWorkspace(workspace);
	}
}